<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>Zabbix 拓扑图渲染示例</title>
<script src="https://unpkg.com/cytoscape/dist/cytoscape.min.js"></script>
<style>
  #cy {
    width: 800px;
    height: 600px;
    border: 1px solid #ccc;
    display: block;
    margin: 20px auto;
  }
</style>
</head>
<body>

<h2 style="text-align:center;">Zabbix 拓扑图（根据 JSON 渲染）</h2>
<div id="cy"></div>

<script>
// 你提供的 JSON 数据
const mapData = {
  "mapid": "2",
  "canvas": { "width": "800", "height": "600" },
  "background": "0",
  "elements": [
    {
      "selementid": "18",
      "elementtype": "0",
      "iconid_off": "150",
      "iconid_on": "0",
      "label": [
        { "content": "192.168.8.131" },
        { "content": "(192.168.8.131)" },
        { "content": "正常", "attributes": { "fill": "#009900" } }
      ],
      "label_location": "-1",
      "x": "250",
      "y": "250",
      "iconid_disabled": "0",
      "iconid_maintenance": "0",
      "elementsubtype": "0",
      "areatype": "0",
      "viewtype": "0",
      "use_iconmap": "1",
      "evaltype": "0",
      "elements": [ { "hostid": "10690", "elementName": "fcn-virtual-machine" } ],
      "tags": [],
      "permission": 2,
      "selementid_orig": "18",
      "elementtype_orig": "0",
      "elementsubtype_orig": "0",
      "label_type": "0",
      "icon": "150",
      "highlight": null,
      "actions": "{\"type\":\"map_element\",\"data\":{\"sysmapid\":\"2\",\"selementid\":\"18\"}}"
    },
    {
      "selementid": "19",
      "elementtype": "0",
      "iconid_off": "150",
      "iconid_on": "0",
      "label": [
        { "content": "sunflvm" },
        { "content": "(192.168.8.130)" },
        { "content": "问题发生在 3", "attributes": { "fill": "#CC0000" } }
      ],
      "label_location": "-1",
      "x": "450",
      "y": "250",
      "iconid_disabled": "0",
      "iconid_maintenance": "0",
      "elementsubtype": "0",
      "areatype": "0",
      "viewtype": "0",
      "use_iconmap": "1",
      "evaltype": "0",
      "elements": [ { "hostid": "10689", "elementName": "sunflvm" } ],
      "tags": [],
      "permission": 2,
      "selementid_orig": "19",
      "elementtype_orig": "0",
      "elementsubtype_orig": "0",
      "label_type": "0",
      "icon": "150",
      "highlight": null,
      "actions": "{\"type\":\"map_element\",\"data\":{\"sysmapid\":\"2\",\"selementid\":\"19\"}}"
    }
  ],
  "links": [],
  "shapes": [],
  "aria_label": "automap, 2 中的 1 处于问题状态, 问题总计 3. 主机, 状态 问题, sunflvm\n(192 168 8 130), 问题发生在 3. 主机, 状态 OK, 192 168 8 131\n(192 168 8 131). ",
  "label_location": "0",
  "timestamp": "2025-07-06 16:58:50"
};

// 解析节点元素，转换成 Cytoscape 格式
const cyElements = [];

// 辅助函数：拼接标签多行文本
function joinLabels(labelArray) {
  return labelArray.map(l => l.content).join('\n');
}

mapData.elements.forEach(el => {
  // 解析节点颜色（取最后一个标签的fill属性作为颜色）
  let fillColor = '#009900'; // 默认绿色
  for (let i = el.label.length - 1; i >= 0; i--) {
    if (el.label[i].attributes && el.label[i].attributes.fill) {
      fillColor = el.label[i].attributes.fill;
      break;
    }
  }

  cyElements.push({
    data: { id: el.selementid, label: joinLabels(el.label) },
    position: { x: parseInt(el.x), y: parseInt(el.y) },
    style: {
      'background-color': fillColor,
      'color': '#fff',
      'text-wrap': 'wrap',
      'text-max-width': 120,
      'text-valign': 'center',
      'text-halign': 'center',
      'font-size': 12,
      'width': 80,
      'height': 80,
      'shape': 'roundrectangle',
      'border-color': '#333',
      'border-width': 1
    }
  });
});

// 如果有连接线，也可以解析，这里为空
mapData.links.forEach(link => {
  cyElements.push({
    data: {
      id: 'link' + link.id,
      source: link.selementid1,
      target: link.selementid2
    }
  });
});

const cy = cytoscape({
  container: document.getElementById('cy'),
  elements: cyElements,
  style: [
    {
      selector: 'node',
      style: {
        'label': 'data(label)',
        'background-color': 'data(style.background-color)',
        'color': 'data(style.color)',
        'text-wrap': 'wrap',
        'text-valign': 'center',
        'text-halign': 'center',
        'font-size': 12,
        'width': 80,
        'height': 80,
        'shape': 'roundrectangle',
        'border-color': '#333',
        'border-width': 1
      }
    },
    {
      selector: 'edge',
      style: {
        'width': 3,
        'line-color': '#ccc',
        'target-arrow-color': '#ccc',
        'target-arrow-shape': 'triangle',
        'curve-style': 'bezier'
      }
    }
  ],
  layout: {
    name: 'preset'  // 使用预设的坐标，不自动布局
  }
});





</script>

</body>
</html>